package com.xiaomaoguai.loadbalance;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.ReentrantReadWriteLock;

/**
 * @fileName: LoadBalance.java
 * @author: WeiHui.Zhang
 * @date: 2016-11-07  14:27
 * @version: v1.0.0
 */
public class LoadBalance {

	Logger LOGGER = LoggerFactory.getLogger(LoadBalance.class);

	private static final Long LongValue = (long) (0 - Integer.MIN_VALUE);
	// 锁
	private ReentrantReadWriteLock rwLock = new ReentrantReadWriteLock();
	/**
	 * k-service,v-nextToUseIndex(使用哪个资源)
	 */
	private Map<String, AtomicInteger> machineNextUseIndex = new HashMap<>();
	/**
	 * k-service,v-分布式环境中的资源
	 */
	private Map<String, List<MachineResource>> machineLists = new HashMap<>();

	private static LoadBalance loadBalance = new LoadBalance();

	public static LoadBalance getInstance() {
		return loadBalance;
	}

	/**
	 * 系统启动，或 zookeeper 节点 数据更新后 执行
	 *
	 * @param service
	 * @param serviceURL
	 */
	private void addMachineResource(String service, String serviceURL) {
		try {
			rwLock.writeLock().lock();
			List<MachineResource> machineResources = machineLists.get(service);
			if (machineResources == null || machineResources.isEmpty()) {
				machineResources = new ArrayList<>();
				machineNextUseIndex.put(service, new AtomicInteger(-1));
			}
			machineResources.add(new MachineResource(serviceURL));
			machineLists.put(service, machineResources);
		} finally {
			rwLock.writeLock().unlock();
		}
	}

	/**
	 * 系统启动，或 zookeeper 节点 数据更新后 执行
	 *
	 * @param service
	 * @param serviceURL
	 */
	public void delMachine(String service, String serviceURL) {
		// 先获取锁
		LOGGER.info("del Machine:" + service + " " + serviceURL);
		try {
			rwLock.writeLock().lock();
			// 如果是删除，那必须之前已经存在，否则没有必要继续
			List<MachineResource> machineList = machineLists.get(service);
			if (null != machineList) {
				MachineResource machine = new MachineResource(serviceURL);
				int index = machineList.indexOf(machine);
				if (-1 != index) {
					machineList.remove(index);
					if (machineList.isEmpty()) {
						machineNextUseIndex.remove(service);
					}
				}
			}
		} finally {
			// 后释放锁
			rwLock.writeLock().unlock();
		}
	}

	private MachineResource getMachineResource(String service) {
		MachineResource targetMachine = null;
		try {
			rwLock.readLock().lock();
			// 拿取机器列表
			List<MachineResource> machineList = machineLists.get(service);
			if (null == machineList) {
				throw new Exception("no machineList found for :" + service);
			}
			// 计算机器下标
			AtomicInteger index = machineNextUseIndex.get(service);
			int newIndex = index.incrementAndGet();// [-2147483648,
			// 修正
			if (newIndex < 0) {// 务必要进行修正// 最大值的话，就要重新开始,否则会成为负数
				newIndex = (int) ((long) newIndex + LongValue);
			}
			// 应用
			newIndex = newIndex % machineList.size();
			// 拿取目标machine
			targetMachine = machineList.get(newIndex);
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			rwLock.readLock().unlock();
		}
		return targetMachine;
	}

	public static void main(String[] args) {
		LoadBalance instance = LoadBalance.getInstance();

		instance.addMachineResource("HelloService", "http://localhost:8080/crsServer/hessian/IImageInfoServern1");
		instance.addMachineResource("HelloService", "http://localhost:8080/crsServer/hessian/IImageInfoServern2");
		instance.addMachineResource("HelloService", "http://localhost:8080/crsServer/hessian/IImageInfoServern3");
		instance.addMachineResource("HelloService", "http://localhost:8080/crsServer/hessian/IImageInfoServern4");
		instance.addMachineResource("HelloService", "http://localhost:8080/crsServer/hessian/IImageInfoServern5");
		instance.addMachineResource("HelloService", "http://localhost:8080/crsServer/hessian/IImageInfoServern6");
		instance.addMachineResource("HelloService", "http://localhost:8080/crsServer/hessian/IImageInfoServern7");
		instance.addMachineResource("HelloService", "http://localhost:8080/crsServer/hessian/IImageInfoServern8");
		instance.addMachineResource("HelloService", "http://localhost:8080/crsServer/hessian/IImageInfoServern9");
		instance.addMachineResource("HelloService", "http://localhost:8080/crsServer/hessian/IImageInfoServern10");

		int i = 10;
		while (i-- > 0) {
			System.out.println(instance.getMachineResource("HelloService"));
		}
	}
}
